/*
Copyright [2020] [https://www.xiaonuo.vip]

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Snowy采用APACHE LICENSE 2.0开源协议，您在使用过程中，需要注意以下几点：

1.请不要删除和修改根目录下的LICENSE文件。
2.请不要删除和修改Snowy源码头部的版权声明。
3.请保留源码和相关描述文件的项目出处，作者声明等。
4.分发源码时候，请注明软件出处 https://gitee.com/xiaonuobase/snowy
5.在修改包名，模块名称，项目代码等时，请注明软件出处 https://gitee.com/xiaonuobase/snowy
6.若您的项目无法满足以上几点，可申请商业授权，获取Snowy商业授权许可，请在官网购买授权，地址为 https://www.xiaonuo.vip
 */
package vip.xiaonuo.modular.stockbalance.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Console;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import vip.xiaonuo.core.consts.CommonConstant;
import vip.xiaonuo.core.enums.CommonStatusEnum;
import vip.xiaonuo.core.exception.ServiceException;
import vip.xiaonuo.core.factory.PageFactory;
import vip.xiaonuo.core.pojo.page.PageResult;
import vip.xiaonuo.core.util.PoiUtil;
import vip.xiaonuo.modular.stockbalance.entity.StockBalance;
import vip.xiaonuo.modular.stockbalance.enums.StockBalanceExceptionEnum;
import vip.xiaonuo.modular.stockbalance.mapper.StockBalanceMapper;
import vip.xiaonuo.modular.stockbalance.param.StockBalanceParam;
import vip.xiaonuo.modular.stockbalance.result.StockBalanceResult;
import vip.xiaonuo.modular.stockbalance.service.StockBalanceService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 库存余额service接口实现类
 *
 * @author czw
 * @date 2022-07-28 16:41:37
 */
@Service
public class StockBalanceServiceImpl extends ServiceImpl<StockBalanceMapper, StockBalance> implements StockBalanceService {

    @Override
    public PageResult<StockBalanceParam> page(StockBalanceParam stockBalanceParam) {
        QueryWrapper<StockBalanceParam> queryWrapper = new QueryWrapper<>();
        if (ObjectUtil.isNotNull(stockBalanceParam)) {

            // 根据产品名称 查询
            if (ObjectUtil.isNotEmpty(stockBalanceParam.getProIds())) {
                queryWrapper.inSql("a.pro_id", stockBalanceParam.getProIds());
            }
            // 根据仓库名称 查询
            if (ObjectUtil.isNotEmpty(stockBalanceParam.getWarHouId())) {
                queryWrapper.eq("a.war_hou_id", stockBalanceParam.getWarHouId());
            }
        }
        queryWrapper.orderByDesc("a.create_time");
        return new PageResult<>(baseMapper.page(PageFactory.defaultPage(), queryWrapper));
    }

    @Override
    public List<StockBalance> list(StockBalanceParam stockBalanceParam) {
        return this.list();
    }

    @Override
    public void add(StockBalanceParam stockBalanceParam) {
        StockBalance stockBalance = new StockBalance();
        BeanUtil.copyProperties(stockBalanceParam, stockBalance);
        this.save(stockBalance);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(List<StockBalanceParam> stockBalanceParamList) {
        stockBalanceParamList.forEach(stockBalanceParam -> {
            this.removeById(stockBalanceParam.getId());
        });
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void edit(StockBalanceParam stockBalanceParam) {
        StockBalance stockBalance = this.queryStockBalance(stockBalanceParam);
        BeanUtil.copyProperties(stockBalanceParam, stockBalance);
        this.updateById(stockBalance);
    }

    @Override
    public StockBalance detail(StockBalanceParam stockBalanceParam) {
        return this.queryStockBalance(stockBalanceParam);
    }

    /**
     * 获取库存余额
     *
     * @author czw
     * @date 2022-07-28 16:41:37
     */
    private StockBalance queryStockBalance(StockBalanceParam stockBalanceParam) {
        StockBalance stockBalance = this.getById(stockBalanceParam.getId());
        if (ObjectUtil.isNull(stockBalance)) {
            throw new ServiceException(StockBalanceExceptionEnum.NOT_EXIST);
        }
        return stockBalance;
    }

    @Override
    public void export(StockBalanceParam stockBalanceParam) {
        List<StockBalance> list = this.list(stockBalanceParam);
        PoiUtil.exportExcelWithStream("SnowyStockBalance.xls", StockBalance.class, list);
    }

    /*
     * 作者名称：王宗
     * 用于出库入库
     */

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addStockBalance(List<StockBalanceParam> stockBalanceParamList) {
        // 添加校验
        stockBalanceParamList.forEach(stockBalanceParam -> {
            checkParam(stockBalanceParam);
        });
        //新增的余额
        List<StockBalance> addStock = new ArrayList<>();
        //编辑的余额
        List<StockBalance> editStock = new ArrayList<>();
        //查找所有仓库余额
        List<StockBalance> stockBalanceList = this.list();
        //将前端传来的余额列表根据仓库归类 id:仓库id value: 余额列表
        Map<Long,List<StockBalanceParam>> stockBalanceParamMap=stockBalanceParamList.stream().collect(Collectors.groupingBy(StockBalanceParam::getWarHouId));
        //将数据库查询的余额列表根据仓库归类 id:仓库id value: 余额列表
        Map<Long, List<StockBalance>> stockBalanaceMap= stockBalanceList.stream().collect(Collectors.groupingBy(StockBalance::getWarHouId));
        //根据key: 仓库id 循环前端传来的余额列表
        for (Long key:stockBalanceParamMap.keySet()){
            //数据库余额列表下 该仓库没有库存余额
            if(ObjectUtil.isNull(stockBalanaceMap.get(key))){
                //获取该仓库下的余额列表
                List<StockBalanceParam> stockBalanceParams=stockBalanceParamMap.get(key);
                if (ObjectUtil.isNotEmpty(stockBalanceParams)){
                    //将余额列表根据产品id归类
                    Map<Long,List<StockBalanceParam>> stockBalanceGroupByProId =stockBalanceParams.stream().collect(Collectors.groupingBy(StockBalanceParam::getProId));
                    for (Long proId:stockBalanceGroupByProId.keySet()){
                        final long[] num = {0};
                        StockBalance stockBalanceNew = new StockBalance();
                        //循环相同产品 累加数量
                        stockBalanceGroupByProId.get(proId).forEach(item->{
                            num[0] = num[0] +item.getStoNum();
                            BeanUtil.copyProperties(item, stockBalanceNew);
                        });
                        //将相同仓库和产品的余额归为一条余额
                        stockBalanceNew.setStoNum(num[0]);
                        addStock.add(stockBalanceNew);
                    }
                }

            }
            //数据库余额列表下 该仓库存在库存余额
            if (ObjectUtil.isNotNull(stockBalanaceMap.get(key))){
                //获取该仓库下的前端传来的余额列表
                List<StockBalanceParam> stockBalanceParamLists=stockBalanceParamMap.get(key);
                //将同一仓库的余额列表根据产品id归类 id:产品id value: 余额列表
                Map<Long,List<StockBalanceParam>> stockBalanceParamGroupByProId=stockBalanceParamLists.stream().collect(Collectors.groupingBy(StockBalanceParam::getProId));
                //获取该仓库下的数据库的余额列表
                List<StockBalance> stockBalanceLists=stockBalanaceMap.get(key);
                //key:产品id value：对应的余额
                Map<Long,StockBalance> stockBalanceGroupByProId=stockBalanceLists.stream().collect(Collectors.toMap(StockBalance::getProId,a->a,(k1,k2)->k1));
                for(Long keys:stockBalanceParamGroupByProId.keySet()){
                    final long[] num = {0};
                    StockBalance stockBalanceNew = new StockBalance();
                    //累加同一产品的数量
                    stockBalanceParamGroupByProId.get(keys).forEach(item->{
                        num[0] = num[0] +item.getStoNum();
                        BeanUtil.copyProperties(item, stockBalanceNew);
                    });
                    //若原先该产品存在余额
                    if (ObjectUtil.isNotEmpty(stockBalanceGroupByProId.get(keys))){
                        stockBalanceNew.setId(stockBalanceGroupByProId.get(keys).getId());
                        //原来的余额数+累加数量
                        stockBalanceNew.setStoNum(stockBalanceGroupByProId.get(keys).getStoNum()+num[0]);
                        editStock.add(stockBalanceNew);
                    }
                    //若原先该产品不存在余额
                    if (ObjectUtil.isEmpty(stockBalanceGroupByProId.get(keys))){
                        stockBalanceNew.setStoNum(num[0]);
                        addStock.add(stockBalanceNew);
                    }
                }
            }
        }
        //保存新增的余额
        this.saveBatch(addStock);
        //保存编辑的余额
        this.updateBatchById(editStock);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteStockBalance(List<StockBalanceParam> stockBalanceParamList) {
        // 添加校验
        stockBalanceParamList.forEach(stockBalanceParam -> {
            checkParam(stockBalanceParam);
        });
        //查找该仓库下各个产品余额
        QueryWrapper<StockBalance> sbqw = new QueryWrapper<>();
        List<StockBalance> stockBalanceList = this.list();
        Map<Long, List<StockBalance>> stockMap1= stockBalanceList.stream().collect(Collectors.groupingBy(StockBalance::getWarHouId));
        List<Long> deleteBalanceList = new ArrayList<>();
        List<StockBalance> editBalanceList = new ArrayList<>();
        stockBalanceParamList.forEach(stockBalanceParam -> {
            StockBalance stockBalance = null;
            for (Long key:stockMap1.keySet()){
                if (key.equals(stockBalanceParam.getWarHouId())){
                    List<StockBalance> list=stockMap1.get(key);
                    // 根据 仓库和产品查询数据库中是否存在 key:产品id  value：库存余额
                    Map<Long, StockBalance> stockMap = list.stream().collect(Collectors.toMap(StockBalance::getProId, a -> a, (k1, k2) -> k1));
                    stockBalance =stockMap.get(stockBalanceParam.getProId());
                }
            }
            //如果没有查到,则出现异常，不得出库
            if (ObjectUtil.isNull(stockBalance)) {
                throw new ServiceException(2, "库存出错,操作已撤回");
            }
            // 查到的话进行一个比较，若库存大于出库数，进行入库
            if (stockBalance.getStoNum() < stockBalanceParam.getStoNum()) {
                //库存数量不够，不能进行出库
                throw new ServiceException(3, "库存出错,操作已撤回");
            }
            // 正常出库
            stockBalance.setStoNum(stockBalance.getStoNum() - stockBalanceParam.getStoNum());
            // 如果库存为0,则删除记录
            if (stockBalance.getStoNum() == 0) {
                deleteBalanceList.add(stockBalance.getId());
            }
            //如果还有库存，对仓库进行修改
            editBalanceList.add(stockBalance);
        });
        this.removeByIds(deleteBalanceList);
        this.updateBatchById(editBalanceList);
    }

    private void checkParam(StockBalanceParam stockBalanceParam) {
        if(ObjectUtil.isEmpty(stockBalanceParam.getWarHouId())){
            throw new ServiceException(1,"仓库为空,请先选择仓库");
        }
        if(ObjectUtil.isEmpty(stockBalanceParam.getProId())){
            throw new ServiceException(2,"产品为空,请选择产品");
        }
        if(ObjectUtil.isEmpty(stockBalanceParam.getStoNum())){
            throw new ServiceException(3,"产品数目为空,请输入数量");
        }
    }

}
